package com.wetao.lib_common.net;

import android.content.Context;

import com.facebook.stetho.okhttp3.StethoInterceptor;
import com.wetao.lib_common.AppConfig;
import com.wetao.lib_common.Constants;
import com.wetao.lib_common.api.BaseApi;
import com.wetao.lib_common.greendao.DBUtils;
import com.wetao.lib_common.greendao.model.HttpCacheItem;
import com.wetao.lib_common.net.cookies.CookiesManager;
import com.wetao.lib_common.utils.ComUtil;
import com.wetao.lib_common.utils.ConstantUtils;
import com.wetao.lib_common.utils.LogUtils;
import com.wetao.lib_common.utils.SPUtils;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.cert.CertificateException;
import java.text.SimpleDateFormat;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import okhttp3.Cache;
import okhttp3.CacheControl;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Protocol;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okhttp3.logging.HttpLoggingInterceptor;
import okio.Buffer;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.converter.scalars.ScalarsConverterFactory;

/**
 * 网络请求 工具
 */
public class ServerUtils {
    private static final int TIME_OUT = 8 * 1000;//链接超时时间
    private volatile static BaseApi mBaseApi;
    private static File cacheFile = new File(AppConfig.PATH_CACHE);
    private static Cache cache = new Cache(cacheFile, 1024 * 1024 * 50);



    private static Context mContext;

    public static void init(Context context) {
        mContext = context;
    }

    public static BaseApi getCommonApi() {
        try {
            if (mBaseApi == null) {
                synchronized (ServerUtils.class) {
                    if (mBaseApi == null) {
                        mBaseApi = createService(BaseApi.class, AppConfig.BASE_URL);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return mBaseApi;
    }

    private static <S> S createService(Class<S> serviceClass, String url) throws Exception {
        Retrofit.Builder builder =
                new Retrofit.Builder()
                        .baseUrl(url)
                        .client(httpClient.build())
                        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                        .addConverterFactory(ScalarsConverterFactory.create())
                        .addConverterFactory(GsonConverterFactory.create());
        Retrofit retrofit = builder.build();
        return retrofit.create(serviceClass);
    }

    private static Interceptor cacheInterceptor = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            if (!ComUtil.isNetworkConnected()) {
                request = request.newBuilder()
                        .cacheControl(CacheControl.FORCE_CACHE)
                        .build();
            }
            Response response = chain.proceed(request);
            if (ComUtil.isNetworkConnected()) {
                int maxAge = 0;
                // 有网络时, 不缓存, 最大保存时长为0
                response.newBuilder()
                        .header("Cache-Control", "public, max-age=" + maxAge)
                        .removeHeader("Pragma")
                        .build();
            } else {
                // 无网络时，设置超时为1周
                int maxStale = 60 * 60 * 24 * 7;
                response.newBuilder()
                        .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
                        .removeHeader("Pragma")
                        .build();
            }
            return response;
        }
    };


    /**
     * 将http请求数据缓存
     */
    private static Interceptor mRewriteCacheControlInterceptor = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            String url = request.url().toString(); //获取请求URL
            Buffer buffer = new Buffer();
            String params = null;
            if (request.body()!=null){
                request.body().writeTo(buffer);
                params = buffer.readString(Charset.forName("UTF-8")); //获取请求参数
            }

            Response response;

            String userId = SPUtils.getInstance().getString(Constants.USER_ID_KEY);
            String xToken = SPUtils.getInstance().getString(Constants.HEAD_XTOKEN);
            if (ComUtil.isNetworkConnected()) {
                int maxAge = 0;
                //如果网络正常，执行请求。
                Response originalResponse = chain.proceed(request);
                //获取MediaType，用于重新构建ResponseBody
                MediaType type = originalResponse.body().contentType();
                //获取body字节即响应，用于存入数据库和重新构建ResponseBody
                byte[] bs = originalResponse.body().bytes();
                response = originalResponse.newBuilder()
                        .removeHeader("Pragma")
                        .removeHeader("Cache-Control")
                        .header("Cache-Control", "no-cache, max-age=" + maxAge)
                        //重新构建body，原因在于body只能调用一次，之后就关闭了。
                        .body(ResponseBody.create(type, bs))
                        .build();
             //   LogUtils.i("req = " +url);
             //   LogUtils.i("req params = " + params);
            //    LogUtils.i("req response = " + new String(bs, "UTF-8"));
                if (response.isSuccessful()) {
                    if (url.contains("querySubjectBySectionId")){
//                    将响应插入数据库
                        DBUtils.getInstance(mContext).insertHttpCacheItem(new HttpCacheItem(null, userId, url, params, new String(bs, "UTF-8"), xToken, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(System
                                .currentTimeMillis())));
                    }
                }
            } else {
                //没有网络的时候，由于Okhttp没有缓存post请求，所以不要调用chain.proceed(request)，会导致连接不上服务器而抛出异常（504）
                HttpCacheItem httpCacheItem = DBUtils.getInstance(mContext).getHttpCacheItem(userId, xToken, url, params);
                if(null != httpCacheItem) {
                    String b = httpCacheItem.getResponse();//cacheDao.queryResponse(url, params); //读出响应
                    LogUtils.i("OkHttp no network request:" + url);
                    LogUtils.i("OkHttp no network request method:" + request.method());
                    LogUtils.i("OkHttp no network response body:" + b);
                    int maxStale = 60 * 60 * 24 * 28;
                    //构建一个新的response响应结果
                    response = new Response.Builder()
                            .removeHeader("Pragma")
                            .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
                            .body(ResponseBody.create(MediaType.parse("application/json"), b.getBytes()))
                            .request(request)
                            .protocol(Protocol.HTTP_1_1)
                            .code(200)
                            .message("Success")
                            .build();
                }else{
                    int maxStale = 60 * 60 * 24 * 28;
                    response = new Response.Builder()
                            .removeHeader("Pragma")
                            .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
                            .body(ResponseBody.create(MediaType.parse("application/json"), ""))
                            .request(request)
                            .protocol(Protocol.HTTP_1_1)
                            .code(504)
                            .message("fail")
                            .build();
                }

            }
            return response;
        }
    };


    private static OkHttpClient.Builder httpClient =
            new OkHttpClient.Builder()
                    .addNetworkInterceptor(new StethoInterceptor())//添加Stetho的拦截器
                    //设置超时
                    .readTimeout(TIME_OUT, TimeUnit.MILLISECONDS)
                    .writeTimeout(TIME_OUT, TimeUnit.MILLISECONDS)
                    .connectTimeout(TIME_OUT, TimeUnit.MILLISECONDS)
                    .addInterceptor(RequestInterceptor.getInstance())//网络请求 统一拦截
                    .addInterceptor(getLogInterceptor())
                    .sslSocketFactory(getSSLSocketFactory())
                    //设置缓存
                    .addNetworkInterceptor(mRewriteCacheControlInterceptor)
                    .addInterceptor(mRewriteCacheControlInterceptor)
                    .cache(cache)
                    //设置cookies
                    .cookieJar(new CookiesManager())
                    .hostnameVerifier(org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);


    private static HttpLoggingInterceptor getLogInterceptor() {
        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
        if (ConstantUtils.isAppDebug()) {
            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        } else {
            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.NONE);
        }
        return loggingInterceptor;
    }

    /**
     * 不验证证书
     *
     * @return
     * @throws
     */
    private static SSLSocketFactory getSSLSocketFactory() {
        //创建一个不验证证书链的证书信任管理器。
        final TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
            @Override
            public void checkClientTrusted(
                    java.security.cert.X509Certificate[] chain,
                    String authType) throws CertificateException {
            }

            @Override
            public void checkServerTrusted(
                    java.security.cert.X509Certificate[] chain,
                    String authType) throws CertificateException {
            }

            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return new java.security.cert.X509Certificate[0];
            }
        }};

        final SSLContext sslContext;
        try {
            sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, trustAllCerts,
                    new java.security.SecureRandom());
            return sslContext
                    .getSocketFactory();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
